//
// Created by tang on 23-3-4.
//

#include "font_mgr.hpp"
#include <imgui.h>
#include <imgui_internal.h>
#include <json/json.hpp>
#include <utils/io_tools.hpp>
#include <utils/path_tools.hpp>
#include "core/assert.hpp"
#include "imgui_freetype.h"
#include <imgui_backend/imgui_impl_opengl3.h>

/*-codegen-target-*/

//
struct FontOption {
    std::string          name;
    int                  size {};
    int                  index {};
    std::vector<ImWchar> ranges;
    bool                 bold {};

    NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT (FontOption, name, size, index, ranges, bold);
};

struct FontCollection {
    std::string             id;
    std::vector<FontOption> values;

    NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT (FontCollection, id, values);
};

// font manager data
static std::vector<std::pair<std::string, ImFont*>> fonts;

void FontManager::init (f32 scale)
{
    using namespace nlohmann;

    std::string cfg_path = "fonts_config.json"_AP;
    std::string content  = ReadTextFile (cfg_path);

    auto obj = json::parse (content);

    std::string fonts_dir;
    obj["asset_dir"].get_to (fonts_dir);

//    L_INFO (content.c_str ());

    std::vector<FontCollection> collection;
    obj["fonts"].get_to (collection);

    // clean first
    auto &io = ImGui::GetIO ();
    io.Fonts->Clear ();

    for (auto &font: collection) {
        const std::string id = font.id;
        ImFont *result = nullptr;

        for (auto &f: font.values) {
            std::string font_full_path = fonts_dir + '/' + f.name;
            font_full_path = GetAssetsPath (font_full_path.c_str());

            PI_ASSERT(!f.ranges.empty () && f.ranges.size () % 2 == 0);
            f.ranges.push_back (0);

            ImFontConfig cfg {};
            strcpy(cfg.Name, f.name.c_str());
            cfg.FontNo = f.index;
            cfg.MergeMode = (result != nullptr);
            cfg.PixelSnapH = true;
            cfg.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LoadColor | ImGuiFreeTypeBuilderFlags_Bitmap;
            if (f.bold)
                cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold;
            L_DEBUG("Loading font: %s (%dpx %s)", f.name.c_str(), f.size, f.bold ? "Bold" : "");

            result = io.Fonts->AddFontFromFileTTF (font_full_path.c_str(), f.size * scale, &cfg, f.ranges.data());
            PI_ASSERT (result != NULL);
        }
        fonts.emplace_back (std::pair<std::string, ImFont*>(id, result));
//        strcpy((char*)result->ConfigData->Name, id.c_str());
    }
    PI_ASSERT (io.Fonts->Build());
//    // update font names
//    for (auto const &x: fonts) {
//        if (x.second->ConfigData)
//            strcpy((char*)x.second->ConfigData->Name, x.first.c_str());
//    }
    ImGui_ImplOpenGL3_CreateFontsTexture();
}

std::vector<std::string> FontManager::get_font_ids () const
{
    return std::vector<std::string> ();
}

void FontManager::use_fonts (std::string_view name) const {
    auto it = std::find_if(begin(fonts), end(fonts), [name](auto const &id) { return id.first == name; });
    if (it != end(fonts)) {
        ImGui::SetCurrentFont (it->second);
    }
}

void FontManager::use_fonts (int index) const {
    if (0 <= index && index < (int)fonts.size()) {
        ImGui::SetCurrentFont (fonts.at (index).second);
    }
}
